package br.edu.unifei.mestrado.unfold;

import java.util.HashMap;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import br.edu.unifei.mestrado.commons.graph.RelationshipWrapper;
import br.edu.unifei.mestrado.commons.mn.TempRelationships;
import br.edu.unifei.mestrado.commons.partition.AbstractPartition;
import br.edu.unifei.mestrado.commons.partition.AbstractPartitionIndex;
import br.edu.unifei.mestrado.commons.partition.EdgeCache;

public class PartitionUnfold extends AbstractPartition {

	private Logger logger = LoggerFactory.getLogger(this.getClass());

	/**
	 * Estrutura de dados PARTITION.
	 * 
	 *id_set, EdgeCache
	 */
	private Map<Integer, EdgeCache> sets = new HashMap<Integer, EdgeCache>();

	public PartitionUnfold(int level, int k, AbstractPartitionIndex index) {
		super(level, k, index);
		for (int id = 0; id < k; id++) {
			sets.put(id, new EdgeCache(id));
		}
	}

	public void addEdgeToSet(int setId, RelationshipWrapper edge) {
		super.addEdgeToCut(edge);
		EdgeCache set = sets.get(setId);
		if (set != null) {
			set.addEdge(edge);
		} else {
			logger.error("ERRO: SET ERRADO PARA ADICIONAR A ARESTA " + edge);
		}
	}

	public void removeEdgeFromSet(int setId, RelationshipWrapper edge) {
		super.removeEdgeFromCut(edge);
		removeEdgeOnlyFromSet(setId, edge);
	}

	/**
	 * Método usado somente para excluir a aresta do set, pq o node saiu desse set e foi para outro.<br>
	 * Ele é assim, pq pode ser que a aresta ainda continua no corte por causa de outro set.
	 * 
	 * @param setId
	 * @param edge
	 */
	public void removeEdgeOnlyFromSet(int setId, RelationshipWrapper edge) {
		EdgeCache set = sets.get(setId);
		if (set != null) {
			set.removeEdge(edge);
		} else {
			logger.error("ERRO: SET ERRADO PARA REMOVER A ARESTA " + edge);
		}
	}

	/**
	 * Busca as arestas de um determinado setId.
	 * 
	 * @param setId
	 * @return
	 */
	public Iterable<RelationshipWrapper> queryEdges(Integer setId) {
		EdgeCache set = sets.get(setId);
		if (set != null) {
			return set.getEdges();
		} else {
			throw new RuntimeException("ERRO: SET " + setId + " ERRADO PARA QUERY");
		}
	}

	/**
	 * Busca o cutWeight de um determinado setId.
	 * 
	 * @param setId
	 * @return
	 */
	public int getCutWeightBySetId(int setId) {
		EdgeCache set = sets.get(setId);
		if (set != null) {
			return set.getEdgeCut();
		} else {
			throw new RuntimeException("ERRO: SET " + setId + " ERRADO PARA QUERY");
		}
	}

	public void print() {
		super.printSets();
		logger.info("Arestas PartitionUnfold: {}", new Object() {
			@Override
			public String toString() {
				StringBuffer b = new StringBuffer();
				for (Integer setId : sets.keySet()) {
					EdgeCache set = sets.get(setId);
					b.append("\n\tEdesg Set_" + setId + ": ");
					for (RelationshipWrapper edge : set.getEdges()) {
						b.append(edge.getId() + ", ");
					}
				}
				return b.toString();
			}
		});
	}
}
